package com.prometheus.config;

import com.prometheus.aspectj.CounterAspectj;
import com.prometheus.aspectj.HistogramAspectj;
import com.prometheus.aspectj.SummaryAspectj;
import io.prometheus.client.exporter.MetricsServlet;
import io.prometheus.client.filter.MetricsFilter;
import io.prometheus.client.hotspot.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import javax.servlet.Servlet;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * @author: Alan
 * @date: 2021/5/18 13:16
 */
@ConditionalOnProperty(value = "alan.prometheus.enable", matchIfMissing = true)
@Configuration
public class PrometheusMetricConfig {

    private static Logger log = LoggerFactory.getLogger(PrometheusMetricConfig.class);

    /**
     * 初始化默认指标
     * @return
     */
    @Bean
    public ApplicationRunner metricExport() {
        return new MetricInitRunnable();
    }

    /**
     * Aop
     * @return
     */
    @Bean
    public CounterAspectj counterAspectj() {
        return new CounterAspectj();
    }

    @Bean
    public HistogramAspectj histogramAspectj() {
        return new HistogramAspectj();
    }

    @Bean
    public SummaryAspectj summaryAspectj() {
        return new SummaryAspectj();
    }

    /**
     * 暴露 servlet 和添加 filter监测
     */
    @ConditionalOnProperty(value = "shareit.prometheus.enable-servlet-and-filter-export", matchIfMissing = true)
    @ConditionalOnClass(value = {Filter.class, Servlet.class})
    public static class ServletConfig {

        @Bean
        public FilterRegistrationBean shareitMetricServlet() {
            FilterRegistrationBean registrationBean = new FilterRegistrationBean();
            registrationBean.setFilter(new MetricsFilter());
            registrationBean.setUrlPatterns(Collections.singletonList("/*"));
            Map<String, String> param = new HashMap<>();
            param.put("metric-name", "MetricFilter");
            param.put("help", "metric filter for all request");
            param.put("buckets", "0.005,0.01,0.025,0.05,0.075,0.1,0.25,0.5,0.75,1,2.5,5,7.5,10");
            param.put("path-components", "5");
            registrationBean.setInitParameters(param);
            log.info("create MetricFilter bean");
            return registrationBean;
        }

        @Bean
        public ServletRegistrationBean shareitMetrisServlet() {
            ServletRegistrationBean servletBean = new ServletRegistrationBean();
            servletBean.addUrlMappings("/metrics");
            MetricsServlet servlet = new MetricsServlet();
            servletBean.setServlet(servlet);
            log.info("create MetricServlet bean");
            return servletBean;
        }
    }

    private static class MetricInitRunnable implements ApplicationRunner {

        @Override
        public void run(ApplicationArguments args) {
            new StandardExports().register(); //cpu和内存
            new MemoryPoolsExports().register(); //虚拟机内存
            new MemoryAllocationExports().register(); //gc前后内存对比
            new BufferPoolsExports().register(); //buffer池大小，主要关注非堆内存
            new GarbageCollectorExports().register(); //垃圾回收器
            new ThreadExports().register(); //线程
            new ClassLoadingExports().register(); //classload
        }
    }


}
